#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#define MAX_CMD_LEN 1024
#define MAX_ARG_NUM 128
void parse_cmd(char *cmd, char **args) {
    int i = 0;
    char *token = strtok(cmd, " ");
    while (token != NULL) {
        args[i++] = token;
        token = strtok(NULL, " ");
    }
    args[i] = NULL;
}
int main() {
    char cmd[MAX_CMD_LEN];
    char *args[MAX_ARG_NUM];
    int cmd_idx = 0;
    int history_size = 0;
    char *history[MAX_CMD_LEN];
    while (1) {
        printf("mysh$ ");
        fflush(stdout);
        fgets(cmd, MAX_CMD_LEN, stdin);
        cmd[strlen(cmd)-1] = '\0';
        // 记录历史命令
        if (strcmp(cmd, "") != 0) {
            history[history_size++] = strdup(cmd);
            cmd_idx = history_size;
        }
        // 处理特殊命令
        if (strcmp(cmd, "exit") == 0) {
            break;
        } else if (strcmp(cmd, "history") == 0) {
            int n = 10;  // 默认显示最近的 10 条命令
            char *token = strtok(NULL, " ");
            if (token != NULL) {
                n = atoi(token);
            }
            if (n > history_size) {
                n = history_size;
            }
            for (int i = history_size - n; i < history_size; i++) {
                printf("%d %s\n", i+1, history[i]);
            }
            continue;
        } else if (strcmp(cmd, "!!") == 0) {
            if (history_size == 0) {
                printf("No commands in history.\n");
                continue;
            }
            strcpy(cmd, history[history_size-1]);
        } else if (strncmp(cmd, "!", 1) == 0) {
            int n = atoi(cmd + 1);
            if (n <= 0 || n > history_size) {
                printf("Invalid command number.\n");
                continue;
            }
            strcpy(cmd, history[n-1]);
        } else if (strncmp(cmd, "cd", 2) == 0) {
            char *dir = strtok(cmd + 2, " ");
            if (dir == NULL) {
                printf("cd: missing directory.\n");
                continue;
            }
            if (chdir(dir) == -1) {
                printf("cd: %s: No such file or directory.\n", dir);
            }
            continue;
        }
        // 解析命令行参数
        parse_cmd(cmd, args);
        // 处理重定向
        int fd_in = STDIN_FILENO;
        int fd_out = STDOUT_FILENO;
        int fd_err = STDERR_FILENO;
        int i = 0;
        while (args[i] != NULL) {
            if (strcmp(args[i], "<") == 0) {
                char *file = args[i+1];
                if (file == NULL) {
                    printf("Missing input file name.\n");
                    break;
                }
                fd_in = open(file, O_RDONLY);
                if (fd_in == -1) {
                    printf("%s: No such file or directory.\n", file);
                    break;
                }
                args[i] = NULL;
                i += 2;
            } else if (strcmp(args[i], ">") == 0) {
                char *file = args[i+1];
                if (file == NULL) {
                    printf("Missing output file name.\n");
                    break;
                }
                fd_out = open(file, O_WRONLY|O_CREAT|O_TRUNC, 0666);
                if (fd_out == -1) {
                    printf("%s: Cannot create file.\n", file);
                    break;
                }
                args[i] = NULL;
                i += 2;
            } else if (strcmp(args[i], "2>") == 0) {
                char *file = args[i+1];
                if (file == NULL) {
                    printf("Missing error file name.\n");
                    break;
                }
                fd_err = open(file, O_WRONLY|O_CREAT|O_TRUNC, 0666);
                if (fd_err == -1) {
                    printf("%s: Cannot create file.\n", file);
                    break;
                }
                args[i] = NULL;
                i += 2;
            } else {
                i++;
            }
        }
        // 处理管道
        int pipefd[2];
        int need_pipe = 0;
        i = 0;
        while (args[i] != NULL) {
            if (strcmp(args[i], "|") == 0) {
                args[i] = NULL;
                need_pipe = 1;
                if (pipe(pipefd) == -1) {
                    perror("pipe");
                    exit(1);
                }
                break;
            }
            i++;
        }
        // 执行命令
        pid_t pid = fork();
        if (pid == -1) {
            perror("fork");
            exit(1);
        } else if (pid == 0) {
            // 子进程
            if (need_pipe) {
                close(pipefd[0]);
                if (dup2(pipefd[1], STDOUT_FILENO) == -1) {
                    perror("dup2");
                    exit(1);
                }
            }
            if (fd_in != STDIN_FILENO) {
                if (dup2(fd_in, STDIN_FILENO) == -1) {
                    perror("dup2");
                    exit(1);
                }
                close(fd_in);
            }
            if (fd_out != STDOUT_FILENO) {
                if (dup2(fd_out, STDOUT_FILENO) == -1) {
                    perror("dup2");
                    exit(1);
                }
                close(fd_out);
            }
            if (fd_err != STDERR_FILENO) {
                if (dup2(fd_err, STDERR_FILENO) == -1) {
                    perror("dup2");
                    exit(1);
                }
                close(fd_err);
            }
            execvp(args[0], args);
            perror(args[0]);
            exit(1);
        } else {
            // 父进程
            if (need_pipe) {
                close(pipefd[1]);
                if (dup2(pipefd[0], STDIN_FILENO) == -1) {
                    perror("dup2");
                    exit(1);
                }
                close(pipefd[0]);
            }
            waitpid(pid, NULL, 0);
        }
    }
    return 0;
}
